﻿using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using SharpAnalyzer.Entities;
using SharpAnalyzer.Utilities;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace SharpAnalyzer.Analyzers
{
    internal sealed class StatementsAnalyzer : CSharpSyntaxWalker
    {
        private int counter;

        public StatementsAnalyzer()
          : base(SyntaxWalkerDepth.Node)
        {
        }

        public int Calculate(Member node)
        {
            Verify.NotNull(() => node);

            BlockSyntax body = MemberBodySelector.FindBody(node);
            if (body != null)
                Visit(body);
            CalculateConstructorStatements(node);
            CalculateCompilerGeneratedPropertyStatements(node);
            return counter;
        }

        private void CalculateConstructorStatements(Member node)
        {
            ConstructorDeclarationSyntax declarationSyntax;
            if (node.Kind != MemberKind.Constructor ||
                (declarationSyntax = node.SyntaxNode as ConstructorDeclarationSyntax) == null ||
                declarationSyntax.Initializer == null)
                return;
            Visit(declarationSyntax.Initializer);
            checked { ++counter; }
        }

        private void CalculateCompilerGeneratedPropertyStatements(Member node)
        {
            switch (node.Kind)
            {
                case MemberKind.GetProperty:
                case MemberKind.SetProperty:
                    if (MemberBodySelector.FindBody(node) != null)
                        break;
                    checked { ++counter; }
                    break;
            }
        }

        public override void VisitInitializerExpression(InitializerExpressionSyntax node)
        {
            base.VisitInitializerExpression(node);
            checked { counter += node.Expressions.Count; }
        }

        public override void VisitUsingDirective(UsingDirectiveSyntax node)
        {
            base.VisitUsingDirective(node);
            checked { ++counter; }
        }

        public override void VisitBreakStatement(BreakStatementSyntax node)
        {
            base.VisitBreakStatement(node);
            checked { ++counter; }
        }

        public override void VisitCheckedStatement(CheckedStatementSyntax node)
        {
            base.VisitCheckedStatement(node);
            checked { ++counter; }
        }

        public override void VisitContinueStatement(ContinueStatementSyntax node)
        {
            base.VisitContinueStatement(node);
            checked { ++counter; }
        }

        public override void VisitDoStatement(DoStatementSyntax node)
        {
            base.VisitDoStatement(node);
            checked { ++counter; }
        }

        public override void VisitEmptyStatement(EmptyStatementSyntax node)
        {
            base.VisitEmptyStatement(node);
            checked { ++counter; }
        }

        public override void VisitExpressionStatement(ExpressionStatementSyntax node)
        {
            base.VisitExpressionStatement(node);
            checked { ++counter; }
        }

        public override void VisitFixedStatement(FixedStatementSyntax node)
        {
            base.VisitFixedStatement(node);
            checked { ++counter; }
        }

        public override void VisitForEachStatement(ForEachStatementSyntax node)
        {
            base.VisitForEachStatement(node);
            checked { ++counter; }
        }

        public override void VisitForStatement(ForStatementSyntax node)
        {
            base.VisitForStatement(node);
            checked { ++counter; }
        }

        public override void VisitGlobalStatement(GlobalStatementSyntax node)
        {
            base.VisitGlobalStatement(node);
            checked { ++counter; }
        }

        public override void VisitGotoStatement(GotoStatementSyntax node)
        {
            base.VisitGotoStatement(node);
            checked { ++counter; }
        }

        public override void VisitIfStatement(IfStatementSyntax node)
        {
            base.VisitIfStatement(node);
            checked { ++counter; }
        }

        public override void VisitLabeledStatement(LabeledStatementSyntax node)
        {
            base.VisitLabeledStatement(node);
            checked { ++counter; }
        }

        public override void VisitLocalDeclarationStatement(LocalDeclarationStatementSyntax node)
        {
            base.VisitLocalDeclarationStatement(node);
            checked { ++counter; }
        }

        public override void VisitLockStatement(LockStatementSyntax node)
        {
            base.VisitLockStatement(node);
            checked { ++counter; }
        }

        public override void VisitReturnStatement(ReturnStatementSyntax node)
        {
            base.VisitReturnStatement(node);
            checked { ++counter; }
        }

        public override void VisitSwitchStatement(SwitchStatementSyntax node)
        {
            base.VisitSwitchStatement(node);
            checked { ++counter; }
        }

        public override void VisitThrowStatement(ThrowStatementSyntax node)
        {
            base.VisitThrowStatement(node);
            checked { ++counter; }
        }

        public override void VisitUnsafeStatement(UnsafeStatementSyntax node)
        {
            base.VisitUnsafeStatement(node);
            checked { ++counter; }
        }

        public override void VisitUsingStatement(UsingStatementSyntax node)
        {
            base.VisitUsingStatement(node);
            checked { ++counter; }
        }

        public override void VisitWhileStatement(WhileStatementSyntax node)
        {
            base.VisitWhileStatement(node);
            checked { ++counter; }
        }

        public override void VisitYieldStatement(YieldStatementSyntax node)
        {
            base.VisitYieldStatement(node);
            checked { ++counter; }
        }
    }
}
